package org.jeecg.modules.sistersophie.facade.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.sistersophie.config.AccountTypeEnums;
import org.jeecg.modules.sistersophie.config.ChangeDirectionEnums;
import org.jeecg.modules.sistersophie.config.PaymentStatusEnums;
import org.jeecg.modules.sistersophie.entity.AccountInfo;
import org.jeecg.modules.sistersophie.entity.AccountTransaction;
import org.jeecg.modules.sistersophie.entity.CourseInfo;
import org.jeecg.modules.sistersophie.entity.CourseStudentInfo;
import org.jeecg.modules.sistersophie.facade.AccountInfoFacade;
import org.jeecg.modules.sistersophie.facade.AccountTransactionFacade;
import org.jeecg.modules.sistersophie.facade.CourseInfoFacade;
import org.jeecg.modules.sistersophie.facade.CourseStudentFacade;
import org.jeecg.modules.sistersophie.model.request.AccountTransactionCancelRequest;
import org.jeecg.modules.sistersophie.model.response.AccountTransactionResponse;
import org.jeecg.modules.sistersophie.model.vo.TransactionCourseVO;
import org.jeecg.modules.sistersophie.service.IAccountTransactionService;
import org.jeecg.modules.sistersophie.service.ICourseInfoService;
import org.jeecg.modules.sistersophie.service.ICourseStudentInfoService;
import org.jeecg.modules.sistersophie.service.ITeacherInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class AccountTransactionFacadeService implements AccountTransactionFacade {

    @Autowired
    private IAccountTransactionService transactionService;

    @Autowired
    private AccountInfoFacade accountInfoFacade;

    @Autowired
    private ICourseInfoService courseInfoService;

    @Autowired
    private CourseStudentFacade courseStudentFacade;

    @Transactional
    public boolean cancel(AccountTransactionCancelRequest request){
       AccountTransaction transaction =  transactionService.getById(request.getId());
        if(ObjectUtils.isEmpty(transaction)){
            throw new RuntimeException("Account Transaction does not exist");
        }
        if(transaction.getIsCancel() != null && transaction.getIsCancel().intValue() != 0){
            throw new RuntimeException("Transaction cancelled");
        }
        if(transaction.getCCancel() != null && transaction.getCCancel().intValue() != 0){
            throw new RuntimeException("Transaction cannot be cancelled");
        }
        AccountInfo accountInfo = accountInfoFacade.selectByStudentAndType(transaction.getStudentId(), AccountTypeEnums.TYPE_1.getType());
        if(ObjectUtils.isEmpty(accountInfo)){
            throw new RuntimeException("Account information does not exist");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //设置该交易为取消
        transaction.setIsCancel(1);
        transaction.setUpdateTime(new Date());
        AccountTransaction accountTransaction = new AccountTransaction();
        BeanUtils.copyProperties(transaction,accountTransaction);
        accountTransaction.setId(null);
        accountTransaction.setChangeBeforeAmount(accountInfo.getAvailableAmount());
        accountTransaction.setRemark("cancel");
        int num = -1;
        //根据操作类型回滚资金
        if(transaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_ADD.getType()){
            if(transaction.getCourseId() != null && transaction.getCourseId() > 0){
                 //课程资金取消流程
                //1.取消冻结
                unFreezeCourseAmount(accountInfo,transaction);
                accountInfo = accountInfoFacade.selectByStudentAndType(transaction.getStudentId(), AccountTypeEnums.TYPE_1.getType());
                String extParam = transaction.getExtParam();
                if(StringUtils.isBlank(extParam)){
                    throw new RuntimeException("operation failed");
                }
                JSONObject extObj = JSONObject.parseObject(extParam);
                CourseStudentInfo courseStudentInfo = courseStudentFacade.selectById(extObj.getInteger("courseStudentId"));
                courseStudentInfo.setPayStatus(PaymentStatusEnums.CANCEL_PAYMENT.getStatus());
                courseStudentInfo.setUpdateTime(new Date());
                courseStudentInfo.setUpdateName(sysUser.getUsername());
                courseStudentFacade.updateInfo(courseStudentInfo);
            }
            if(accountInfo.getAvailableAmount().compareTo(accountTransaction.getChangeAmount()) < 0){
                throw new RuntimeException("operation failed");
            }
            accountTransaction.setChangeBeforeAmount(accountInfo.getAvailableAmount());
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_SUB.getType());
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().subtract(accountTransaction.getChangeAmount()));
            num = accountInfoFacade.subAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());

        }else if(transaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_SUB.getType()){
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_ADD.getType());
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().add(accountTransaction.getChangeAmount()));
            num = accountInfoFacade.addAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }else if(transaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_FREE.getType()){
            if(accountInfo.getFreeAmount().compareTo(accountTransaction.getChangeAmount()) < 0){
                throw new RuntimeException("operation failed");
            }
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_UNFREE.getType());
            accountTransaction.setChangeAfterAmount(accountInfo.getAmount());
            num = accountInfoFacade.unFreeAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }else if(transaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_UNFREE.getType()){
            if(accountInfo.getAvailableAmount().compareTo(accountTransaction.getChangeAmount()) < 0){
                throw new RuntimeException("operation failed");
            }
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_FREE.getType());
            accountTransaction.setChangeAfterAmount(accountInfo.getAmount());
            num = accountInfoFacade.freeAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }
        if(num <= 0){
            throw new RuntimeException("cancel failed");
        }

        accountTransaction.setCreateName(sysUser.getUsername());
        accountTransaction.setCreateTime(new Date());
        accountTransaction.setUpdateName(sysUser.getUsername());
        accountTransaction.setUpdateTime(new Date());
        accountTransaction.setIsDelete(0);
        accountTransaction.setIsCancel(0);
        accountTransaction.setCCancel(1);
        transactionService.save(accountTransaction);
        transactionService.updateById(transaction);
        if(transaction.getCourseId() > 0){
            //TODO 回滚课程支付状态
        }
       return true;
    }

    @Transactional
    void unFreezeCourseAmount(AccountInfo accountInfo,AccountTransaction transaction){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        AccountTransaction accountTransaction = new AccountTransaction();
        BeanUtils.copyProperties(transaction,accountTransaction);
        accountTransaction.setId(null);
        accountTransaction.setChangeBeforeAmount(accountInfo.getAvailableAmount());
        if(accountInfo.getFreeAmount().compareTo(accountTransaction.getChangeAmount()) < 0){
            throw new RuntimeException("operation failed");
        }
        accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_UNFREE.getType());
        accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().add(accountTransaction.getChangeAmount()));
        accountTransaction.setCreateName(sysUser.getUsername());
        accountTransaction.setCreateTime(new Date());
        accountTransaction.setUpdateName(sysUser.getUsername());
        accountTransaction.setUpdateTime(new Date());
        accountTransaction.setIsDelete(0);
        accountTransaction.setIsCancel(0);
        accountTransaction.setCCancel(1);
        accountTransaction.setRemark("cancel unfreeze");
        transactionService.save(accountTransaction);
        int num = accountInfoFacade.unFreeAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        if(num <= 0){
            throw new RuntimeException("operation failed");
        }
        accountInfo.setAvailableAmount(accountInfo.getAvailableAmount().add(transaction.getChangeAmount()));
        accountInfo.setFreeAmount(accountInfo.getFreeAmount().subtract(transaction.getChangeAmount()));
    }

    @Transactional
    public boolean addCredit(AccountTransaction accountTransaction){
        //查询账户信息
        AccountInfo accountInfo = accountInfoFacade.selectByStudentAndType(accountTransaction.getStudentId(), AccountTypeEnums.TYPE_1.getType());
        if(ObjectUtils.isEmpty(accountInfo)){
            throw new RuntimeException("Account information does not exist");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        accountTransaction.setAccountId(accountInfo.getId());
        accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_ADD.getType());
        accountTransaction.setChangeBeforeAmount(accountInfo.getAvailableAmount());
        accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().add(accountTransaction.getChangeAmount()));
        accountTransaction.setInvoiceId(0);
        accountTransaction.setIsCancel(0);
        accountTransaction.setCCancel(0);
        accountTransaction.setCourseId(0);
        accountTransaction.setCreateName(sysUser.getUsername());
        accountTransaction.setCreateTime(new Date());
        accountTransaction.setUpdateName(sysUser.getUsername());
        accountTransaction.setUpdateTime(new Date());
        accountTransaction.setIsDelete(0);
        int num = accountInfoFacade.addAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        if(num <= 0){
            throw new RuntimeException("add Credit failed");
        }
        transactionService.save(accountTransaction);
        return true;
    }

    @Transactional
    public boolean changeCredit(AccountTransaction accountTransaction,Integer invoiceId,Integer courseId,Integer ccancel,String remark,String extParam){
        //查询账户信息
        AccountInfo accountInfo = accountInfoFacade.selectByStudentAndType(accountTransaction.getStudentId(), AccountTypeEnums.TYPE_1.getType());
        if(ObjectUtils.isEmpty(accountInfo)){
            throw new RuntimeException("Account information does not exist");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        accountTransaction.setAccountId(accountInfo.getId());

        accountTransaction.setChangeBeforeAmount(accountInfo.getAvailableAmount());
        if(invoiceId !=null){
            accountTransaction.setInvoiceId(invoiceId);
        }else{
            accountTransaction.setInvoiceId(0);
        }
        if(courseId != null){
            accountTransaction.setCourseId(courseId);
        }else{
            accountTransaction.setCourseId(0);
        }
        accountTransaction.setIsCancel(0);
        accountTransaction.setCCancel(ccancel);
        accountTransaction.setCreateName(sysUser.getUsername());
        accountTransaction.setCreateTime(new Date());
        accountTransaction.setUpdateName(sysUser.getUsername());
        accountTransaction.setUpdateTime(new Date());
        accountTransaction.setIsDelete(0);
        if(StringUtils.isNotBlank(remark)){
            accountTransaction.setRemark(remark);
        }
        if(StringUtils.isNotBlank(extParam)){
            accountTransaction.setExtParam(extParam);
        }
        int num = -1;
        if(accountTransaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_FREE.getType() ){
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().subtract(accountTransaction.getChangeAmount()));
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_FREE.getType());
            num = accountInfoFacade.freeAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }else  if(accountTransaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_ADD.getType() ){
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_ADD.getType());
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().add(accountTransaction.getChangeAmount()));
            num = accountInfoFacade.addAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }else if(accountTransaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_SUB.getType() ){
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().subtract(accountTransaction.getChangeAmount()));
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_SUB.getType());
            num = accountInfoFacade.subAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }else if(accountTransaction.getChangeDirection().intValue() == ChangeDirectionEnums.TYPE_UNFREE.getType() ){
            accountTransaction.setChangeAfterAmount(accountInfo.getAvailableAmount().add(accountTransaction.getChangeAmount()));
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_UNFREE.getType());
            num = accountInfoFacade.unFreeAccount(accountInfo.getId(),accountTransaction.getChangeAmount(),accountInfo.getVersion());
        }
        if(num <= 0){
            throw new RuntimeException("Credit failed");
        }
        transactionService.save(accountTransaction);
        return true;
    }


    public IPage<AccountTransactionResponse> pageList(AccountTransaction accountTransaction, Integer pageNo,
                                                    Integer pageSize,
                                                      HttpServletRequest req){
        //查询账户信息
        AccountInfo accountInfo = accountInfoFacade.selectByStudentAndType(accountTransaction.getStudentId(), AccountTypeEnums.TYPE_1.getType());
        if(ObjectUtils.isEmpty(accountInfo)){
            throw new RuntimeException("Account information does not exist");
        }
        accountTransaction.setAccountId(accountInfo.getId());
        QueryWrapper<AccountTransaction> queryWrapper = QueryGenerator.initQueryWrapper(accountTransaction, req.getParameterMap());
        Page<AccountTransaction> page = new Page<AccountTransaction>(pageNo, pageSize);
        queryWrapper.orderByDesc("id");
        List<AccountTransactionResponse> transactionResponseList = new ArrayList<>();
        IPage<AccountTransactionResponse> resultPage = new Page<>();
        IPage<AccountTransaction> pageList = transactionService.page(page,queryWrapper);
        resultPage.setRecords(transactionResponseList);
        resultPage.setTotal(pageList.getTotal());
        resultPage.setSize(pageList.getSize());
        resultPage.setCurrent(pageList.getCurrent());
        resultPage.setPages(pageList.getPages());
        List<AccountTransaction> transactionList = pageList.getRecords();
        String currency = "$";
        if(transactionList != null){
            for(AccountTransaction transaction : transactionList){
                AccountTransactionResponse response = new AccountTransactionResponse();
                BeanUtils.copyProperties(transaction,response);
                if(ObjectUtils.isNotEmpty(response.getChangeAmount())){
                    response.setStrChangeAmount(currency + NumberUtil.decimalFormat("###,###,##0.00",response.getChangeAmount()));
                }
                if(ObjectUtils.isNotEmpty(response.getChangeAfterAmount())){
                    response.setStrChangeAfterAmount(currency + NumberUtil.decimalFormat("###,###,##0.00",response.getChangeAfterAmount()));
                }
                if(ObjectUtils.isNotEmpty(response.getCreateTime())){
                    response.setStrCreateTime(DateUtil.formatDate(response.getCreateTime()));
                }
                if(ObjectUtils.isNotEmpty(response.getChangeDirection())){
                    //0=冻结 1=增加 2=减少
                    if(response.getChangeDirection().intValue() == 1){
                        response.setDirection("+");
                    } else  if(response.getChangeDirection().intValue() == 2){
                        response.setDirection("-");
                    }
                }else{
                    response.setDirection("");
                }
                if(response.getCourseId() != null && response.getCourseId() > 0){
                    CourseInfo courseInfo =  courseInfoService.getById(response.getCourseId());
                    if(courseInfo != null){
                        TransactionCourseVO courseVO = new TransactionCourseVO();
                        courseVO.setName(courseInfo.getName());
                        courseVO.setTeacher(courseInfo.getTeacherFirstName() + " " + courseInfo.getTeacherLastName());
                        courseVO.setTerm(courseInfo.getTerm());
                        response.setTransactionCourse(courseVO);
                    }
                 }
                transactionResponseList.add(response);
            }
        }
         return resultPage;
    }

}
